from math import floor

from kivy.metrics import inch

class SpaceModel(object):
    """
    This is a 2 dimensional space.
    type: width_inches: float, int
    type: height_inches: float, int
    """
    def __init__(self, top_width_inches, bottom_width_inches, height_inches):
        self.top_width_inches = top_width_inches
        self.bottom_width_inches = bottom_width_inches
        self.height_inches = height_inches
        

class OutdoorSpaceModel(SpaceModel):
    """
    This is a 2 dimensional space on an outdoor target.
    The space also has a distance in yards.
    """
    def __init__(self, top_width_inches, bottom_width_inches, height_inches, distance_yards, description):
        """
        type: width_inches: float, int
        type: height_inches: float, int
        type: distance_yards: float, int
        type: description: str
        """
        SpaceModel.__init__(self, top_width_inches, bottom_width_inches, height_inches)
        self.distance_yards = distance_yards
        self.description = description


class DryFireSpaceModel(object):
    """
    This is a space on an indoor target.
    The space has a cooresponding OutdoorSpaceModel.
    The indoor target has a distance in feet.
    The space has a length in inches.
    """
    def __init__(self, outdoor_space_model, distance_feet):
        """
        type: outdoor_space_model: OutdoorSpaceModel
        type: distance_feet: float, int
        """
        self._outdoor_space_model = outdoor_space_model
        self._distance_feet = distance_feet
        self._height_pixels = 0
        self._top_width_pixels = 0
        self._bottom_width_pixels = 0
        self._pixels_per_inch = inch(1)
        self._recalc()

    # properties

    @property
    def distance_yards(self):
        return self._outdoor_space_model.distance_yards

    @distance_yards.setter
    def distance_yards(self, value):
        """
        type: value: float, int
        """
        if self._distance_yards != value:
            self._distance_yards = value
            self._recalc()
        

    @property
    def description(self):
        return self._outdoor_space_model.description

    @property
    def distance_feet(self):
        return self._distance_feet

    @distance_feet.setter
    def distance_feet(self, value):
        """
        type: value: float, int
        """
        if self._distance_feet != value:
            self._distance_feet = value
            self._recalc()

    @property
    def pixels_per_inch(self):
        return self._pixels_per_inch

    @pixels_per_inch.setter
    def pixels_per_inch(self, value):
        """
        type: value: float, int
        """
        if self._pixels_per_inch != value:
            self._pixels_per_inch = value
            self._recalc()

    @property
    def width_inches(self):
        return max(self.top_width_inches, self.bottom_width_inches)
    @property
    def width_pixels(self):
        return max(self._top_width_pixels, self._bottom_width_pixels)

    @property
    def top_width_pixels(self):
        return self._top_width_pixels
    @property
    def top_width_inches(self):
        return self._outdoor_space_model.top_width_inches

    @property
    def bottom_width_inches(self):
        return self._outdoor_space_model.bottom_width_inches
    @property
    def bottom_width_pixels(self):
        return self._bottom_width_pixels

    @property
    def height_inches(self):
        return self._outdoor_space_model.height_inches
    @property
    def height_pixels(self):
        return self._height_pixels

    # public methods

    def recalc(self, pixels_per_inch=None, indoor_distance_feet=None, outdoor_distance_yards=None):
        if pixels_per_inch is not None:
            self._pixels_per_inch = pixels_per_inch
        if indoor_distance_feet is not None:
            self._distance_feet = indoor_distance_feet
        if outdoor_distance_yards is not None:
            self._outdoor_space_model.distance_yards = outdoor_distance_yards
        self._recalc()

    # private methods
        
    def _recalc(self):
        # moa yards
        outdoor_magnification = 100 / self._outdoor_space_model.distance_yards
        h = self._outdoor_space_model.height_inches * outdoor_magnification
        tw = self._outdoor_space_model.top_width_inches * outdoor_magnification
        bw = self._outdoor_space_model.bottom_width_inches * outdoor_magnification
        h_moa = h / 1.05
        tw_moa = tw / 1.05
        bw_moa = bw / 1.05
        # moa feet
        indoor_magnification = (0.0035 * self._distance_feet)
        h_moa *= indoor_magnification
        tw_moa *= indoor_magnification
        bw_moa *= indoor_magnification
        # pixels hight
        pixels = self._pixels_per_inch * h_moa * 1.05
        self._height_pixels = floor(pixels)
        # pixels top
        pixels = self._pixels_per_inch * tw_moa * 1.05
        self._top_width_pixels = floor(pixels)
        # pixels bottom
        pixels = self._pixels_per_inch * bw_moa * 1.05
        self._bottom_width_pixels = floor(pixels)
